package com.uxsino.simo.indicator.retractor;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.Doubles;
import com.uxsino.commons.utils.config.PropElement;
import com.uxsino.reactorq.model.INDICATOR_TYPE;
import com.uxsino.simo.indicator.CompoundIndicator;
import com.uxsino.simo.indicator.IIndicatorField;
import com.uxsino.simo.indicator.Indicator;
import com.uxsino.simo.networkentity.EntityInfo;
import com.uxsino.simo.query.QueryContext;
import com.uxsino.simo.query.QueryTemplate;
import com.uxsino.simo.utils.ConfigLoadingContext;
import com.uxsino.simo.utils.ConfigPropLoader;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class SNMPMapSumValueRetractor extends CompoundValueRetractor {
    protected  Map<String, String> fieldMapping;

    public SNMPMapSumValueRetractor(){
        super();
        fieldMapping = Maps.newHashMap();
    }

    public void addFieldRetreiver(String fieldName, String propName, IValueRetractor retriever) {
        addFieldRetreiver(fieldName, retriever);
        if (!Strings.isNullOrEmpty(propName)) {
            fieldMapping.put(fieldName, propName);
        }
    }

    @Override
    protected void loadFieldRetractor(Indicator ind, PropElement eFld, ConfigLoadingContext lctxt) {
        ConfigPropLoader loader = new ConfigPropLoader(lctxt);
        IIndicatorField fld = ((CompoundIndicator) ind).getField(eFld.getProp("name"));

        if (fld == null) {
            lctxt.error(eFld.getSourceLocation(), "cannot find field named:{}", eFld.getProp("name"));
            return;
        }
        String fieldParserName = eFld.getProp("parser");
        String propName = eFld.getProp("property");

        IValueRetractor retractor = null;
        try {
            if ("regex".equals(fieldParserName)) {
                String regexPattern = eFld.getProp("pattern");
                retractor = ValueRetractorFactory.createValueRetractor("regex", fld.getFieldType().caseIndType());
                if (regexPattern != null) {
                    ((RegexValueRetractor) retractor).setPattern(regexPattern);
                }
            } else if (fieldParserName != null && fieldParserName.length() != 0) {
                lctxt.error(eFld.getSourceLocation(),
                        "parser type: " + fieldParserName + " is not allowed here. ignored.");
            } else {
                retractor = ValueRetractorFactory.createValueRetractor("", fld.getFieldType().caseIndType());
            }
            loader.loadProperties(retractor, eFld);
            addFieldRetreiver(fld.getName(), propName, retractor);
        } catch (Exception e) {
            lctxt.error(eFld.getSourceLocation(), " error loading retract for field {}\n{}", fld.getName(), e);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object doRetract(EntityInfo entity, QueryContext ctxt, QueryTemplate qt, Object obj) {

        Map<String, Object> record = Maps.newHashMap();
        if (obj == null) {
            return record;
        }
        Map<String, Map<String, String>> map = (Map<String, Map<String, String>>) obj;

        //获取field交集
        List<String> ids = fieldMapping.values().stream().collect(Collectors.toList());
        ids.retainAll(map.keySet());

        if(ids.isEmpty()){
            return record;
        }
        //求索引并集，索引相同才使用
        List<String> subIds = Lists.newArrayList();
        subIds.addAll(map.get(ids.get(0)).keySet().parallelStream().map(idx->idx.replace(ids.get(0) + ".", "")).collect(Collectors.toList()));
        if(ids.size() > 1){
            for (int i = 1; i < ids.size(); i++) {
                String itm = ids.get(i);
                subIds.addAll(map.get(itm).keySet().parallelStream().map(idx->idx.replace(itm + ".", "")).collect(Collectors.toList()));
            }
        }

        //组装数据
        for (Map.Entry<String, IValueRetractor> entry : fieldRetrievers.entrySet()) {
            if(ids.contains(fieldMapping.get(entry.getKey()))){
                if(INDICATOR_TYPE.NUMBER.equals(entry.getValue().getValueType()) || INDICATOR_TYPE.PERCENT.equals(entry.getValue().getValueType())){
                    Optional<Double> result = map.get(fieldMapping.get(entry.getKey())).values().parallelStream().map(v->{
                        try {
                            return Doubles.tryParse(v.toString());
                        } catch (Exception e) {
                            return null;
                        }
                    }).filter(v->v != null).reduce((a,b)->a+b);
                    if(result.isPresent()){
                        record.put(entry.getKey(), result.get());
                    }
                }
            }
        }
        return record;
    }
}
